package com.upb.webserver.common.tools.encryption;

import com.upb.webserver.common.constant.Constant;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.WebServerTools;
import com.upb.webserver.common.tools.encryption.sm2.SM2;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.X500Name;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.regex.Pattern;

/**
 *
 */
@Slf4j
public class P12Manager {

    public static final String ALIAS_PRIVATE_KEY = "key";
    public static final String TYPE_P12 = "PKCS12";

    public static final Pattern JAVA_VERSION = Pattern.compile("([0-9]*.[0-9]*)(.*)?");

    static {

        Security.setProperty("crypto.policy", "unlimited");

        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * @param path
     * @param password
     * @return
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     * @throws IOException
     * @throws KeyStoreException
     * @throws NoSuchProviderException
     * @throws UnrecoverableKeyException
     */
    public static BCECPrivateKey loadPrivateKey(String path, String password) throws NoSuchAlgorithmException,
            CertificateException, IOException, KeyStoreException, NoSuchProviderException, UnrecoverableKeyException {
        KeyStore keyStore = KeyStore.getInstance(TYPE_P12, EccKeyUtil.BC);
        try (FileInputStream in = new FileInputStream(path)) {
            keyStore.load(in, password.toCharArray());
        }

        return (BCECPrivateKey) keyStore.getKey(ALIAS_PRIVATE_KEY, password.toCharArray());
    }


    /**
     * @param key
     * @param password
     * @return
     */
    public static String storeKeyAsP12File(Key key, char[] password) {
        log.info("start exec method [storeKeyAsP12File]");
        FileOutputStream fileOutputStream = null;
        try {
            KeyStore keyStore = KeyStore.getInstance(TYPE_P12);
            keyStore.load(null, null);
            CertAndKeyGen gen = new CertAndKeyGen("RSA", "SHA1WithRSA");
            gen.generate(1024);

            X509Certificate cert = gen.getSelfCertificate(new X500Name("CN=ROOT"), (long) 365 * 24 * 3600);
            X509Certificate[] chain = new X509Certificate[1];
            chain[0] = cert;

            keyStore.setKeyEntry(ALIAS_PRIVATE_KEY, key, password, chain);


            //delete yesterday file
            String yesterdayStr = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now().minusDays(1));
            String yesterdayParentFileName = String.format(Constant.P12_FILE_PARENT_NAME_FORMAT, yesterdayStr);
            File yesterdayParentDirectory = new File(yesterdayParentFileName);
            yesterdayParentDirectory.deleteOnExit();

            //store p12 file
            String nowDateStr = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now());
            String nowDateTimeStr = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
            String fileFullName = String.format(Constant.P12_FILE_NAME_FORMAT, nowDateStr, nowDateTimeStr);
            WebServerTools.createFileIfNotExist(new File(fileFullName), true, true);
            fileOutputStream = new FileOutputStream(fileFullName);
            keyStore.store(fileOutputStream, password);
            return fileFullName;
        } catch (Exception ex) {
            log.info("fail exec method [storeKeyAsP12File]", ex);
            throw new WebServerException(ConstantCode.FAIL_STORE_KEY_FILE);
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (Exception e) {
                    log.info("fail when try to close fileOutputStream", e);
                }
            }
        }
    }


    public static void main(String[] args) {

        try {

//            // 测试字符串
//            String stringToSign = "dskf2329we23w23三ad发发是fksafas;dfkasdf;askdfjaskdjfaksjdfkasjf;ksjf;aksjfkasjdf;askfdjas;kdfj";
//            // 测试密码
//            String password = "p12-password";
//
//            // 使用 SM2 生成公私钥对
//            SM2 sm2 = SM2.newInstance();
//            PrivateKey privateKey = EccKeyUtil.getPrivateKey(sm2.getPrivateKey());
//            String ecPointHex = sm2.getKeyPair().ecPointToHex();
//            System.out.println("Private key : " + sm2.getPrivateKey());
//            System.out.println("ecPointHex : " + ecPointHex);
//
//            // 将私钥保存为 p12 文件，需要使用密码
//
//
//            String fileName = storeKeyAsP12File(privateKey, password.toCharArray());

            // 从生成的 p12 文件读取私钥
            BCECPrivateKey loadPrivateKey = P12Manager.loadPrivateKey("E:\\temp\\0xdaa0a69e1fa92cbfce63473b6ce4189b310d16bc.p12", "123456");
            String loadPrivateKeyHexString = HexUtil.byteToHexUpper(loadPrivateKey.getD().toByteArray());
            System.out.println("Load private key from store file: " + loadPrivateKeyHexString);

            // 使用读取出来的私钥签名
//            String signByPKHex = SignUtil.signByPKHex(loadPrivateKeyHexString, stringToSign.getBytes(StandardCharsets.UTF_8));

//             使用公钥进行验证
//            boolean isVerified = verifyByEcPointHex(ecPointHex, signByPKHex, stringToSign);
//            System.out.println("Generate p12 private key file and verify by public key : " + signByPKHex);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
